﻿// Root idea: http://www.areaprog.com/SP2010/cours-554-spview-setviewxml-modifier-le-schema-xml-d-une-vue-sans-setviewxml
namespace com.crownpack.Extensions.SharePointExtensions
{
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;

    using Microsoft.SharePoint;

    public static class SPViewExtensions
    {
        #region Methods

        /// <summary>
        /// Sets the view's aggregations based upon the supplied schema.
        /// Sample schema:
        /// string schema = "&lt;View&gt;&lt;ViewFields&gt;&lt;FieldRef Name='Attachments' /&gt;&lt;FieldRef Name='cpInitNo' /&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;FieldRef Name='cpInitDscr' /&gt;&lt;FieldRef Name='cpLocationName' /&gt;&lt;FieldRef Name='cpSalesrepName' /&gt;&lt;FieldRef Name='cpPC' /&gt;&lt;FieldRef Name='cpRealDt' /&gt;&lt;FieldRef Name='cpEstTotSavTot' /&gt;&lt;FieldRef Name='cpCustInitNo' /&gt;&lt;/ViewFields&gt;&lt;Query&gt;&lt;GroupBy Collapse='TRUE' GroupLimit='300'&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;/GroupBy&gt;&lt;OrderBy&gt;&lt;FieldRef Name='Created' Ascending='FALSE' /&gt;&lt;/OrderBy&gt;&lt;/Query&gt;&lt;Aggregations Value='On'&gt;&lt;FieldRef Name='cpEstTotSavTot' Type='SUM' /&gt;&lt;/Aggregations&gt;&lt;/View&gt;";
        /// Example: 
        /// SPView view = spList.CreateView( "abc", "Title of View", 100, true, true, SPViewCollection.SPViewType.Html, true );
        /// view.SetQueryXml( schema );
        /// view.SetAggregationXml( schema );
        /// view.SetViewFieldXml( schema );
        /// view.Update();
        /// </summary>
        /// <param name="view"></param>
        /// <param name="schema"></param>
        public static void SetAggregationsXml( this SPView view, string schema )
        {
            setSchemaXml( view, schema, "Aggregations" );
        }

        /// <summary>
        /// Sets the view's mobile based upon the supplied schema.
        /// Sample schema:
        /// string schema = "&lt;View&gt;&lt;ViewFields&gt;&lt;FieldRef Name='Attachments' /&gt;&lt;FieldRef Name='cpInitNo' /&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;FieldRef Name='cpInitDscr' /&gt;&lt;FieldRef Name='cpLocationName' /&gt;&lt;FieldRef Name='cpSalesrepName' /&gt;&lt;FieldRef Name='cpPC' /&gt;&lt;FieldRef Name='cpRealDt' /&gt;&lt;FieldRef Name='cpEstTotSavTot' /&gt;&lt;FieldRef Name='cpCustInitNo' /&gt;&lt;/ViewFields&gt;&lt;Query&gt;&lt;GroupBy Collapse='TRUE' GroupLimit='300'&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;/GroupBy&gt;&lt;OrderBy&gt;&lt;FieldRef Name='Created' Ascending='FALSE' /&gt;&lt;/OrderBy&gt;&lt;/Query&gt;&lt;Aggregations Value='On'&gt;&lt;FieldRef Name='cpEstTotSavTot' Type='SUM' /&gt;&lt;/Aggregations&gt;&lt;/View&gt;";
        /// Example: 
        /// SPView view = spList.CreateView( "abc", "Title of View", 100, true, true, SPViewCollection.SPViewType.Html, true );
        /// view.SetQueryXml( schema );
        /// view.SetAggregationXml( schema );
        /// view.SetViewFieldXml( schema );
        /// view.Update();
        /// </summary>
        /// <param name="view"></param>
        /// <param name="schema"></param>
        public static void SetMobileXml( this SPView view, string schema )
        {
            setSchemaXml( view, schema, "Mobile" );
        }

        /// <summary>
        /// Sets the view's query based upon the supplied schema.
        /// Sample schema:
        /// string schema = "&lt;View&gt;&lt;ViewFields&gt;&lt;FieldRef Name='Attachments' /&gt;&lt;FieldRef Name='cpInitNo' /&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;FieldRef Name='cpInitDscr' /&gt;&lt;FieldRef Name='cpLocationName' /&gt;&lt;FieldRef Name='cpSalesrepName' /&gt;&lt;FieldRef Name='cpPC' /&gt;&lt;FieldRef Name='cpRealDt' /&gt;&lt;FieldRef Name='cpEstTotSavTot' /&gt;&lt;FieldRef Name='cpCustInitNo' /&gt;&lt;/ViewFields&gt;&lt;Query&gt;&lt;GroupBy Collapse='TRUE' GroupLimit='300'&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;/GroupBy&gt;&lt;OrderBy&gt;&lt;FieldRef Name='Created' Ascending='FALSE' /&gt;&lt;/OrderBy&gt;&lt;/Query&gt;&lt;Aggregations Value='On'&gt;&lt;FieldRef Name='cpEstTotSavTot' Type='SUM' /&gt;&lt;/Aggregations&gt;&lt;/View&gt;";
        /// Example: 
        /// SPView view = spList.CreateView( "abc", "Title of View", 100, true, true, SPViewCollection.SPViewType.Html, true );
        /// view.SetQueryXml( schema );
        /// view.SetAggregationXml( schema );
        /// view.SetViewFieldXml( schema );
        /// view.Update();
        /// </summary>
        /// <param name="view"></param>
        /// <param name="schema"></param>
        public static void SetQueryXml( this SPView view, string schema )
        {
            setSchemaXml( view, schema, "Query" );
        }

        public static void SetSchemaXml( this SPView view, string schema )
        {
            XDocument schemaXml = XDocument.Parse( schema );
            MethodInfo setInnerXmlForNode = typeof( SPView ).GetMethod( "SetInnerXmlForNode", BindingFlags.Instance | BindingFlags.NonPublic );

            if ( setInnerXmlForNode == null )
            {
                view.SetViewXml( schema );
            }
            else
            {
                foreach ( XElement child in schemaXml.Root.Elements( ) )
                {
                    setInnerXmlForNode.Invoke( view, new object[ ] { child.Name.LocalName, child.GetContent( ) } );
                }
            }
        }

        /// <summary>
        /// Sets the view's view fields based upon the supplied schema.
        /// Sample schema:
        /// string schema = "&lt;View&gt;&lt;ViewFields&gt;&lt;FieldRef Name='Attachments' /&gt;&lt;FieldRef Name='cpInitNo' /&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;FieldRef Name='cpInitDscr' /&gt;&lt;FieldRef Name='cpLocationName' /&gt;&lt;FieldRef Name='cpSalesrepName' /&gt;&lt;FieldRef Name='cpPC' /&gt;&lt;FieldRef Name='cpRealDt' /&gt;&lt;FieldRef Name='cpEstTotSavTot' /&gt;&lt;FieldRef Name='cpCustInitNo' /&gt;&lt;/ViewFields&gt;&lt;Query&gt;&lt;GroupBy Collapse='TRUE' GroupLimit='300'&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;/GroupBy&gt;&lt;OrderBy&gt;&lt;FieldRef Name='Created' Ascending='FALSE' /&gt;&lt;/OrderBy&gt;&lt;/Query&gt;&lt;Aggregations Value='On'&gt;&lt;FieldRef Name='cpEstTotSavTot' Type='SUM' /&gt;&lt;/Aggregations&gt;&lt;/View&gt;";
        /// Example: 
        /// SPView view = spList.CreateView( "abc", "Title of View", 100, true, true, SPViewCollection.SPViewType.Html, true );
        /// view.SetQueryXml( schema );
        /// view.SetAggregationXml( schema );
        /// view.SetViewFieldXml( schema );
        /// view.Update();
        /// </summary>
        /// <param name="view"></param>
        /// <param name="schema"></param>
        public static void SetViewFieldXml( this SPView view, string schema )
        {
            setSchemaXml( view, schema, "ViewFields" );
        }

        /// <summary>
        /// Sets the view's schema based upon the supplied schema.
        /// Sample schema:
        /// string schema = "&lt;View&gt;&lt;ViewFields&gt;&lt;FieldRef Name='Attachments' /&gt;&lt;FieldRef Name='cpInitNo' /&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;FieldRef Name='cpInitDscr' /&gt;&lt;FieldRef Name='cpLocationName' /&gt;&lt;FieldRef Name='cpSalesrepName' /&gt;&lt;FieldRef Name='cpPC' /&gt;&lt;FieldRef Name='cpRealDt' /&gt;&lt;FieldRef Name='cpEstTotSavTot' /&gt;&lt;FieldRef Name='cpCustInitNo' /&gt;&lt;/ViewFields&gt;&lt;Query&gt;&lt;GroupBy Collapse='TRUE' GroupLimit='300'&gt;&lt;FieldRef Name='cpPrdCat' /&gt;&lt;/GroupBy&gt;&lt;OrderBy&gt;&lt;FieldRef Name='Created' Ascending='FALSE' /&gt;&lt;/OrderBy&gt;&lt;/Query&gt;&lt;Aggregations Value='On'&gt;&lt;FieldRef Name='cpEstTotSavTot' Type='SUM' /&gt;&lt;/Aggregations&gt;&lt;/View&gt;";
        /// Example: 
        /// SPView view = spList.CreateView( "abc", "Title of View", 100, true, true, SPViewCollection.SPViewType.Html, true );
        /// view.SetViewSchemaXml( schema );
        /// view.Update();
        /// </summary>
        /// <param name="view"></param>
        /// <param name="schema"></param>
        public static void SetViewSchemaXml( this SPView view, string schema )
        {
            view.SetAggregationsXml( schema );
            view.SetMobileXml( schema );
            view.SetQueryXml( schema );
            view.SetViewFieldXml( schema );
        }

        static string GetContent( this XElement element )
        {
            return element.DescendantNodes( ).Aggregate(
                new StringBuilder( ),
                ( sb, node ) => sb.Append( node.ToString( SaveOptions.DisableFormatting ) ),
                sb => sb.ToString( )
            );
        }

        static void setSchemaXml( SPView view, string schema, string tagName )
        {
            XmlDocument targetDocument = new XmlDocument( );
            targetDocument.LoadXml( view.SchemaXml );
            XmlElement targetElement = targetDocument.DocumentElement;

            XmlDocument sourceDocument = new XmlDocument( );
            sourceDocument.LoadXml( schema );
            XmlElement sourceElement = sourceDocument.DocumentElement;

            setXmlNode( sourceElement, targetElement, tagName );
            view.SetSchemaXml( targetDocument.OuterXml );
        }

        static void setXmlNode( XmlElement sourceElement, XmlElement targetElement, string xpath )
        {
            XmlNode sourceNode = sourceElement.SelectSingleNode( xpath );
            XmlNode targetNode = targetElement.SelectSingleNode( xpath );
            if ( sourceNode == null || targetNode == null )
                return;

            targetNode.InnerXml = sourceNode.InnerXml;
            foreach ( XmlAttribute attribute in sourceNode.Attributes )
            {
                targetNode.Attributes.RemoveNamedItem( attribute.Name );
                XmlAttribute attrib = targetElement.OwnerDocument.CreateAttribute( attribute.Name );
                attrib.Value = attribute.Value;
                targetNode.Attributes.Append( attrib );
            }
        }

        #endregion Methods
    }
}